class StateMeta(type):

    def __new__(cls, name, base, attrs):
        attrs['check_transition'] = cls.check_transition
        attrs['reset_duration_condition'] = cls.reset_duration_condition

        return super().__new__(cls, name, base, attrs)

    def check_transition(self):
        machine = getattr(self, 'machine')
        for transition in getattr(self, 'transitions'):
            if transition.conditions:
                for condition in transition.conditions:
                    if condition():
                        machine.on_exit()
                        setattr(self, 'is_active', False)
                        machine.current_state = machine.get_state(transition.target)
                        machine.current_state.is_active = True
                        machine.on_enter()
                        return

    def reset_duration_condition(self):
        for transition in getattr(self, 'transitions'):
            if transition.conditions:
                for condition in transition.conditions:
                    if condition.type == 'duration':
                        condition.parameters['start_time'] = None
                        condition.parameters['left_time'] = None
                        machine = getattr(self, 'machine')
                        machine.global_parameters['_left_time'] = None


class State(metaclass=StateMeta):

    def __init__(self, name, machine=None, transitions=None):
        self.transitions = transitions
        if transitions is None:
            self.transitions = []
        self.name = name
        self.machine = machine
        self.is_active = False

    def on_enter(self):
        return

    def on_exit(self):
        return

    def on_process(self, delta):
        return

    def __repr__(self):
        return self.name

    def add_transition(self, transition):
        transition.machine = self.machine
        transition.source = self.name
        self.transitions.append(transition)

    def add_transitions(self, transitions):
        for transition in transitions:
            self.add_transition(transition)
